package main

import (
	"errors"
	"fmt"
)

//闭包

func f1(f func()) {
	fmt.Println("this is f1")
	f()
}

func f2(x, y int) {
	fmt.Println("this is f2")
	fmt.Println(x + y)
}

//定义一个函数对f2进行封装
func f3(f func(int, int)) func() {
	tmp := func() {
		fmt.Println("hello")
	}
	return tmp
}

func lixiang(x int) {
	tmp := func() {
		//先在自己这里面找，然后上级去上级找
		fmt.Println(x)
	}
	tmp()

}
func lixiang1(x func(int, int), m, n int) {
	tmp := func() {
		//先在自己这里面找，然后上级去上级找
		x(m, n)
	}
	tmp() //  相当于 x(m,n)

}

func lixiang2(x func(int, int), m, n int) {
	x(m, n)
}

func lixiang3(x func(int, int), m, n int) func() {
	tmp := func() {
		//先在自己这里面找，然后上级去上级找
		x(m, n)
	}
	return tmp

}

//实现f1(f2)
func f4(f func(int, int), x, y int) func() {
	tmp := func() {
		f(x, y)
	}
	return tmp
}

func add(x, y int) int {
	return x + y
}

func sub(x, y int) int {
	return x - y
}

func do(s string) (func(int, int) int, error) {
	switch s {
	case "+":
		return add, nil
	case "-":
		return sub, nil
	default:
		err := errors.New("无法识别的操作符")
		return nil, err
	}
}

func main() {
	lixiang(100)
	lixiang1(f2, 100, 200)
	lixiang2(f2, 1001, 200)
	ret := lixiang3(f2, 1001, 200)
	ret()

	fmt.Println("f1(f2):")
	//把原来需要传递两个int类型的参数包装成一个不需要传参的函数
	ret1 := f4(f2, 100, 200)
	fmt.Printf("ret1的类型=%T \n", ret1)
	//ret1()
	f1(ret1)

	//函数作为返回值
	addsub, mes := do("+")
	fmt.Println(addsub(300, 200), mes)
	addsub1, mes := do("-")
	fmt.Println(addsub1(500, 200), mes)
	fmt.Println(do("*"))
	//下面部分报错，原因不得而知
	/* addsub, mes := do("*")
	fmt.Println(addsub(300, 200), mes) */

}
